package swagger2

import (
	"bsfswagger/base"
	"gitee.com/chejiangyi/bsfgo/core/utils"
	"strings"
)

type Swagger2Parser struct {
}

func (m *Swagger2Parser) ParserSwagger(json string) *base.Api {
	var swaggerJson Swagger2Json
	utils.JsonUtil.FromJson(json, &swaggerJson)
	api := &base.Api{BasePath: swaggerJson.BasePath, Title: swaggerJson.Info.Title}
	for key1, definition := range swaggerJson.Definitions {
		defer m.catchError(definition)
		model := base.Model{
			Name:        key1,
			Type:        key1,
			Description: definition.Description,
		}
		for key2, propertyJson := range definition.Properties {
			typeName, isArray := m.parsePropertyType(propertyJson)
			property := base.Property{
				Name:        key2,
				Type:        typeName,
				IsArray:     isArray,
				Description: propertyJson.Description,
				Example:     propertyJson.Example,
			}
			model.Properties = append(model.Properties, property)
		}
		api.Models = append(api.Models, model)
	}
	for url, pathInfo := range swaggerJson.Paths {
		for httpMethod, path := range pathInfo {
			method := base.Method{
				Path:        url,
				HttpMethod:  httpMethod,
				Summary:     path.Summary,
				Description: path.Description,
				Consumes:    path.Consumes,
				Produces:    path.Produces,
			}
			for _, parameterJson := range path.Parameters {
				defer m.catchError(parameterJson)
				typeName, isArray := m.parseParameter(parameterJson)
				parameter := base.Parameter{
					Name:        parameterJson.Name,
					Description: parameterJson.Description,
					In:          parameterJson.In,
					Required:    parameterJson.Required,
					Type:        typeName,
					IsArray:     isArray,
					Default:     parameterJson.Default,
				}
				method.Parameters = append(method.Parameters, parameter)
			}
			for code, responseJson := range path.Responses {
				defer m.catchError(responseJson)
				typeName, isArray := m.parseReturnType(responseJson.Schema)
				returnParameter := base.ReturnParameter{
					Description: responseJson.Description,
					Name:        responseJson.Name,
					Code:        code,
					Type:        typeName,
					IsArray:     isArray,
				}
				method.Returns = append(method.Returns, returnParameter)
			}
			api.Methods = append(api.Methods, method)
		}
	}
	return api
}

func (m *Swagger2Parser) parseParameter(perameter ParameterJson) (typeName string, isArray bool) {
	isArray = false
	if perameter.Type == "array" {
		isArray = true
		if !utils.StringUtil.IsEmpty(perameter.Items.Type) {
			typeName = perameter.Items.Type
		}
		if !utils.StringUtil.IsEmpty(perameter.Items.Ref) {
			typeName = m.replaceRef(perameter.Items.Ref)
		}
		return typeName, isArray
	}
	if !utils.StringUtil.IsEmpty(perameter.Type) {
		typeName = perameter.Type
		return typeName, isArray
	}
	return m.parseReturnType(perameter.Schema)
}

func (m *Swagger2Parser) parseReturnType(schema *SchemaJson) (typeName string, isArray bool) {
	isArray = false
	if schema == nil {
		return typeName, isArray
	}
	if schema.Type == "array" {
		isArray = true
		if !utils.StringUtil.IsEmpty(schema.Items.Type) {
			typeName = schema.Items.Type
		}
		if !utils.StringUtil.IsEmpty(schema.Items.Ref) {
			typeName = m.replaceRef(schema.Items.Ref)
		}
		return typeName, isArray
	}

	if !utils.StringUtil.IsEmpty(schema.Ref) {
		typeName = m.replaceRef(schema.Ref)
		return typeName, isArray
	}
	return schema.Type, isArray
}

func (m *Swagger2Parser) parsePropertyType(property PropertyJson) (typeName string, isArray bool) {
	isArray = false
	//if !utils.StringUtil.IsEmpty(property.Format) {
	//	typeName = property.Format
	//	return typeName, isArray
	//}
	if property.Type == "array" {
		isArray = true
		if !utils.StringUtil.IsEmpty(property.Items.Type) {
			typeName = property.Items.Type
		}
		if !utils.StringUtil.IsEmpty(property.Items.Ref) {
			typeName = m.replaceRef(property.Items.Ref)
		}
		return typeName, isArray
	}
	if property.Type == "object" || utils.StringUtil.IsEmpty(property.Type) {
		typeName = m.replaceRef(property.Ref)
		return typeName, isArray
	}
	return property.Type, isArray
}

func (*Swagger2Parser) replaceRef(typeName string) string {
	return strings.Replace(typeName, "#/definitions/", "", -1)
}

func (*Swagger2Parser) catchError(args ...any) {
	if err := recover(); err != nil {
		utils.LogUtil.Error(err, "swagger解析异常:%v", args)
		panic(err)
	}
}
